package cn.dxs.gitee.mvp.presenter.base;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
import android.text.TextUtils;

import com.orhanobut.logger.Logger;

import org.apache.http.conn.ConnectTimeoutException;

import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import cn.dxs.gitee.AppConfig;
import cn.dxs.gitee.AppData;
import cn.dxs.gitee.R;
import cn.dxs.gitee.common.AppEventBus;
import cn.dxs.gitee.dao.DaoSession;
import cn.dxs.gitee.http.UserService;
import cn.dxs.gitee.http.core.AppRetrofit;
import cn.dxs.gitee.http.core.HttpObserver;
import cn.dxs.gitee.http.core.HttpProgressSubscriber;
import cn.dxs.gitee.http.core.HttpResponse;
import cn.dxs.gitee.http.core.HttpSubscriber;
import cn.dxs.gitee.http.error.HttpError;
import cn.dxs.gitee.http.error.HttpErrorCode;
import cn.dxs.gitee.http.error.HttpPageNoFoundError;
import cn.dxs.gitee.http.error.UnauthorizedError;
import cn.dxs.gitee.mvp.contract.base.IBaseContract;
import cn.dxs.gitee.util.NetHelper;
import cn.dxs.gitee.util.PrefUtils;
import retrofit2.Response;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * 层现器基类
 *
 * @author lijian
 * @date 2019-09-21 10:35
 */
public abstract class BasePresenter<V extends IBaseContract.View> implements IBaseContract.Presenter<V> {
    private static final String TAG = "BasePresenter";

    //View
    protected V mView;
    //db Dao
    protected DaoSession daoSession;

    private ArrayList<Subscriber<?>> subscribers;
    private boolean isEventSubscriber = false;
    private boolean isViewInitialized = false;

    private boolean isAttached = false;

    public BasePresenter(DaoSession daoSession) {
        this.daoSession = daoSession;
        subscribers = new ArrayList<>();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {

    }

    @Override
    public void onRestoreInstanceState(Bundle outState) {

    }

    /**
     * 绑定View
     *
     * @param view view
     */
    @Override
    public void attachView(@NonNull V view) {
        mView = view;
        if (isEventSubscriber) AppEventBus.INSTANCE.getEventBus().register(this);
        onViewAttached();
        isAttached = true;
    }

    /**
     * 取消View绑定
     */
    @Override
    public void detachView() {
        mView = null;
        //view 取消绑定时，把请求取消订阅
        for (Subscriber subscriber : subscribers) {
            if (subscriber != null && !subscriber.isUnsubscribed()) {
                subscriber.unsubscribe();
                Logger.d(TAG, "unsubscribe:" + subscriber.toString());
            }
        }
        if (isEventSubscriber) AppEventBus.INSTANCE.getEventBus().unregister(this);
    }

    @Override
    public void onViewInitialized() {
        isViewInitialized = true;
    }

    /**
     * 获取上下文，需在onViewAttached()后调用
     *
     * @return
     */
    @Nullable
    @Override
    public Context getContext() {
        if (mView instanceof Context) {
            return (Context) mView;
        } else if (mView instanceof Fragment) {
            return ((Fragment) mView).getContext();
        } else {
            throw new NullPointerException("BasePresenter:mView is't instance of Context,can't use getContext() method.");
        }
    }

    protected boolean isViewInitialized() {
        return isViewInitialized;
    }


    //--------------------------------------------------------------------------------------------------
    //---Retrofit网络请求-start---------------------------------------------------------------------
    //--------------------------------------------------------------------------------------------------
//    protected LoginService getLoginService() {
//        return AppRetrofit.INSTANCE
//                .getRetrofit(AppConfig.GITEE_BASE_URL, null)
//                .create(LoginService.class);
//    }
//
//    protected LoginService getLoginService(String token) {
//        return AppRetrofit.INSTANCE
//                .getRetrofit(AppConfig.GITEE_API_BASE_URL, token)
//                .create(LoginService.class);
//    }
//
    protected UserService getUserService(String token) {
        return AppRetrofit.INSTANCE
                .getRetrofit(AppConfig.GITEE_API_BASE_URL, token)
                .create(UserService.class);
    }

    /**
     * 发起网络请求，获取用户信息
     *
     * @return
     */
    protected UserService getUserService() {
        return getUserService(AppData.INSTANCE.getAccessToken());
    }
//
//    protected RepoService getRepoService() {
//        return getServices(RepoService.class);
//    }
//
//    protected SearchService getSearchService() {
//        return getServices(SearchService.class);
//    }
//
//    protected OpenHubService getOpenHubService() {
//        return getServices(OpenHubService.class, AppConfig.GITEE_BASE_URL, true);
//    }
//
//    protected IssueService getIssueService() {
//        return getServices(IssueService.class);
//    }
//
//    protected CommitService getCommitService() {
//        return getServices(CommitService.class);
//    }
//
//    protected NotificationsService getNotificationsService() {
//        return getServices(NotificationsService.class);
//    }
//
//    protected GitHubWebPageService getGitHubWebPageService() {
//        return getServices(GitHubWebPageService.class, AppConfig.GITEE_BASE_URL, false);
//    }
//
//    private <T> T getServices(Class<T> serviceClass) {
//        return getServices(serviceClass, AppConfig.GITEE_API_BASE_URL, true);
//    }
//
//    protected <T> T getServices(Class<T> serviceClass, String baseUrl, boolean isJson) {
//        return AppRetrofit.INSTANCE
//                .getRetrofit(baseUrl, AppData.INSTANCE.getAccessToken(), isJson)
//                .create(serviceClass);
//    }
    //--------------------------------------------------------------------------------------------------
    //---Retrofit网络请求-end---------------------------------------------------------------------
    //--------------------------------------------------------------------------------------------------


    /**
     * presenter和view绑定成功
     */
    @CallSuper
    protected void onViewAttached() {

    }

    /**
     * 被观察者
     *
     * @param <T>
     */
    protected interface IObservableCreator<T> {
        /**
         * 创建被观察者
         *
         * @param forceNetWork true：强制网络；false：缓存
         * @return
         */
        Observable<Response<T>> createObservable(boolean forceNetWork);
    }


    /**
     * 一般的rx http请求执行
     *
     * @param observable 被观察者
     * @param subscriber 订阅者(如果为 null 表明不管数据回调)
     * @param <T>
     */
    protected <T> void generalRxHttpExecute(@NonNull Observable<Response<T>> observable, @Nullable HttpSubscriber<T> subscriber) {
        if (subscriber != null) {
            subscribers.add(subscriber);
            observable.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(subscriber);
        } else {
            observable.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new HttpSubscriber<T>());
        }
    }

    /**
     * 一般的rx http请求执行(无请求进度圈，不读取缓存)
     *
     * @param observableCreator 被观察者接口
     * @param httpObserver      观察者
     * @param <T>
     */
    protected <T> void generalRxHttpExecute(@NonNull IObservableCreator<T> observableCreator
            , @NonNull HttpObserver<T> httpObserver) {
        generalRxHttpExecute(observableCreator, httpObserver, false);
    }

    /**
     * 一般的rx http请求执行(无请求进度圈)
     *
     * @param observableCreator 被观察者接口
     * @param httpObserver      观察者
     * @param readCacheFirst    是否优先读取缓存(true：优先读取缓存；false：不读缓存)
     * @param <T>
     */
    protected <T> void generalRxHttpExecute(@NonNull IObservableCreator<T> observableCreator
            , @NonNull HttpObserver<T> httpObserver, final boolean readCacheFirst) {
        generalRxHttpExecute(observableCreator, httpObserver, readCacheFirst, null);
    }

    // 防止死循环
    private Map<String, Integer> requestTimesMap = new HashMap<>();

    /**
     * 一般的rx http请求执行(自己传参数确定是否要请求进度圈)
     *
     * @param observableCreator 被观察者接口
     * @param httpObserver      观察者
     * @param readCacheFirst    是否优先读取缓存(true：优先读取缓存；false：不读缓存)
     * @param progressDialog    进度圈(如果为null，则表示不要进度圈)
     * @param <T>
     */
    protected <T> void generalRxHttpExecute(@NonNull final IObservableCreator<T> observableCreator
            , @NonNull final HttpObserver<T> httpObserver, final boolean readCacheFirst
            , @Nullable final ProgressDialog progressDialog) {
        requestTimesMap.put(observableCreator.toString(), 1);

        // 创建一个临时的http观察者，对传递进来的http观察者进行包装
        // 主要是对“共性”的应答结果进行处理，如服务器返回404、504、401等
        final HttpObserver<T> tempObserver = new HttpObserver<T>() {
            @Override
            public void onError(Throwable error) {
                if (!checkIsUnauthorized(error)) {
                    httpObserver.onError(error);
                }
            }

            @Override
            public void onSuccess(@NonNull HttpResponse<T> response) {
                if (response.isSuccessful()) {
                    // 优先读取缓存，应答是来自缓存的，当前本地网络正常，当前请求发送少于2
                    if (readCacheFirst && response.isFromCache()
                            && NetHelper.INSTANCE.getNetEnabled()
                            && requestTimesMap.get(observableCreator.toString()) < 2) {
                        requestTimesMap.put(observableCreator.toString(), 2);
                        // 发起强制网络请求
                        generalRxHttpExecute(observableCreator.createObservable(true),
                                getHttpSubscriber(this, progressDialog));
                    }
                    httpObserver.onSuccess(response);
                } else if (response.getOriResponse().code() == 404) {
                    onError(new HttpPageNoFoundError());
                } else if (response.getOriResponse().code() == 504) {
                    onError(new HttpError(HttpErrorCode.NO_CACHE_AND_NETWORK));
                } else if (response.getOriResponse().code() == 401) {
                    onError(new UnauthorizedError());
                } else {
                    onError(new Error(response.getOriResponse().message()));
                }
            }
        };

        // 如果缓存可用，先加载缓存，然后从网络加载
        boolean cacheFirstEnable = PrefUtils.isCacheFirstEnable();
//        cacheFirstEnable = cacheFirstEnable || !NetHelper.INSTANCE.getNetEnabled();
        generalRxHttpExecute(observableCreator.createObservable(!cacheFirstEnable || !readCacheFirst),
                getHttpSubscriber(tempObserver, progressDialog));
    }

    /**
     * 获取一个网络请求订阅者
     *
     * @param httpObserver   http观察者
     * @param progressDialog 网络请求时的进度圈，为null时不显示
     * @param <T>            应答结果解析为该泛型
     * @return
     */
    private <T> HttpSubscriber<T> getHttpSubscriber(HttpObserver<T> httpObserver, ProgressDialog progressDialog) {
        if (progressDialog == null) {
            return new HttpSubscriber<>(httpObserver);
        } else {
            return new HttpProgressSubscriber<>(progressDialog, httpObserver);
        }
    }

    // 检查是否是“未授权错误”(true：是；false：否)
    private boolean checkIsUnauthorized(Throwable error) {
        if (error instanceof UnauthorizedError) {
            mView.showErrorToast(error.getMessage());// 显示“未授权错误”的toast
            daoSession.getAuthUserDao().delete(AppData.INSTANCE.getAuthUser());// 本地数据库删除用户信息
            AppData.INSTANCE.setAuthUser(null);// 置空内存用户信息
            AppData.INSTANCE.setLoggedUser(null);// 置空内存中的用户信息
            mView.showLoginPage();// 跳转至登录页面
            return true;
        }
        return false;
    }

    //
//    public void rxDBExecute(@NonNull Runnable runnable){
//        daoSession.rxTx().run(runnable).subscribe();
//    }
//
//
//    @NonNull
//    protected String getLoadTip() {
//        return getContext().getString(R.string.loading).concat("...");
//    }
//
//    protected boolean isLastResponse(@NonNull HttpResponse response) {
//        return response.isFromNetWork() ||
//                !NetHelper.INSTANCE.getNetEnabled();
//    }
//
    @NonNull
    protected String getErrorTip(@NonNull Throwable error) {
        String errorTip = null;
        if (error == null) {
            return errorTip;
        }
        if (error instanceof UnknownHostException) {
            errorTip = getString(R.string.no_network_tip);
        } else if (error instanceof SocketTimeoutException || error instanceof ConnectTimeoutException) {
            errorTip = getString(R.string.load_timeout_tip);
        } else if (error instanceof HttpError) {
            errorTip = error.getMessage();
        } else {
            errorTip = TextUtils.isEmpty(error.getMessage()) ? error.toString() : error.getMessage();
        }
        return errorTip;
    }


    @NonNull
    protected String getString(@StringRes int resId) {
        return getContext().getResources().getString(resId);
    }
//
//    public void setEventSubscriber(boolean eventSubscriber) {
//        isEventSubscriber = eventSubscriber;
//        if(isEventSubscriber && isAttached && !AppEventBus.INSTANCE.getEventBus().isRegistered(this)){
//            AppEventBus.INSTANCE.getEventBus().register(this);
//        }
//    }
//
//    protected void executeSimpleRequest(@NonNull final Observable<Response<ResponseBody>> observable) {
//        HttpObserver<ResponseBody> httpObserver = new HttpObserver<ResponseBody>() {
//            @Override
//            public void onError(Throwable error) {
//                mView.showErrorToast(getErrorTip(error));
//            }
//
//            @Override
//            public void onSuccess(HttpResponse<ResponseBody> response) {
//            }
//        };
//        generalRxHttpExecute(new IObservableCreator<ResponseBody>() {
//            @Override
//            public Observable<Response<ResponseBody>> createObservable(boolean forceNetWork) {
//                return observable;
//            }
//        }, httpObserver);
//    }
//
//    protected void checkStatus(@NonNull Observable<Response<ResponseBody>> observable,
//                               @NonNull final CheckStatusCallback callback) {
//        HttpSubscriber<ResponseBody> httpSubscriber = new HttpSubscriber<>(
//                new HttpObserver<ResponseBody>() {
//                    @Override
//                    public void onError(Throwable error) {
//                    }
//
//                    @Override
//                    public void onSuccess(HttpResponse<ResponseBody> response) {
//                        callback.onChecked(response.isSuccessful());
//                    }
//                }
//        );
//        generalRxHttpExecute(observable, httpSubscriber);
//    }
//
//    protected interface CheckStatusCallback {
//        void onChecked(boolean status);
//    }

}
